Introduction to Messages

[ Back to Win95 ASM Page ]

Messages are at the heart of Windows GUI programming. Almost everything a GUI program does is triggered by messages. Writing a program that repeatedly waits for messages, results in an event-driven style of programming.

Sending and Posting

Usually, message loops are used to dispatch received messages. And these messages are usually dispatched by invoking window procedures. However, messages can be either sent to a window or posted to a thread. Thus a posted message needn't invoke a window procedure. The most obvious example of a posted message that doesn't go to a window is WM_QUIT, which is usually posted with PostQuitMessage.
    Message loops usually wait for messages by calling GetMessage. If any "sent" messages have arrived, GetMessage directly invokes the proper window procedure (bypassing any visible message handling code). If there are any "posted" messages, it returns to the calling program and lets the message loop handle the message. If a window is associated with the message, the proper window procedure is usually invoked via DispatchMessage.
    Some messages do not need to be processed by the message loop. These messages are the ones sent with SendMessage in one thread to a window in the same thread. In this case, the window procedure is invoked directly, as if it were a subroutine. [See More on Messages.]
    Windows produces a lot of messages, but the typical application will provide a custom response to only a small percentage of them. Most of the messages can be classified as notifications--"this happened" or "this is about to happen" messages. A few messages, e.g., WM_PAINT, can be interpreted as commands.

Message identifiers

A message is a packet of information that contains an identifying number. Although we could use raw numbers, by convention we give them all names. These become the "message names".
    The message names/numbers are allocated as follows: The message name WM_USER has the value of 0400h and WM_APP has the value of 8000h.

The example program

Our example program, winclick.asm, responds to left and right mouse button clicks by changing the title bar. Below, we show what's different from the basic GUI program.

Titles

We define two titles and set up our window to display one of them on startup. The window width is made long enough to avoid clipping of the title text.
DEFAULT_STYLE equ WS_VISIBLE + WS_OVERLAPPED + WS_CAPTION + WS_SYSMENU + \
                  WS_THICKFRAME + WS_MINIMIZEBOX + WS_MAXIMIZEBOX 
DEFAULT_EXSTYLE equ WS_EX_WINDOWEDGE + WS_EX_CLIENTEDGE 
DEFAULT_X  equ 100 
DEFAULT_Y  equ 100 
DEFAULT_WIDTH equ 400 
DEFAULT_HEIGHT equ 200 

    .data 

    align 4 

cwargs CREATEARGS <DEFAULT_EXSTYLE,wndclsname,title1,DEFAULT_STYLE, \
          DEFAULT_X,DEFAULT_Y, DEFAULT_WIDTH,DEFAULT_HEIGHT, 0,0, 0, 0> 
title1 db 'Left-click to change title',0 
title2 db 'Restore title by right-clicking',0

Dispatch

The following is one way to dispatch messages. It's not bad because there are so few messages. A bigger set of messages would be easier to handle with an address table.
    Each message handler uses exactly the same argument list block (we could call it the message packet) as WndProc.
    extrn DefWindowProc:near 

    .code
WndProc:
    mov    eax,[esp+4+4]      ; message ID
    cmp    eax,WM_LBUTTONDOWN ; left mouse button pressed
    je     left_mouse_down
    cmp    eax,WM_RBUTTONDOWN ; right mouse button pressed
    je     right_mouse_down
    cmp    eax,WM_DESTROY     ; about to start window destruction
    je     start_destroy
    jmp    DefWindowProc      ; delegate other message processing

Mouse messages

This is how we respond to the mouse messages. The selected title depends on which button is pressed. The code is left unoptimized so that it shows more clearly where the hwnd parameter is coming from. (The +4 skips the stacked EIP, and +0 is the offset of the first argument.)
    extrn  SetWindowText:near 

    .code
left_mouse_down: 
    mov    eax,[esp+4+0] ; get hwnd before changing ESP 
    push   offset title2 
    push   eax 
    call   SetWindowText 

    xor    eax,eax 
    ret    16 

right_mouse_down: 
    mov    eax,[esp+4+0] ; get hwnd before changing ESP 
    push   offset title1 
    push   eax 
    call   SetWindowText 

    xor    eax,eax 
    ret    16